"use strict";

import {Native} from "./native.js";
import {Task} from "./task.js";

/**
 * http常用操作
 * @static
 * @author GuoHua Liu
 * @copyright Copyright © 2019 GuoHua Liu. All rights reserved.
 */
class http {

    /**
     * 支持浏览器:是<br>
     * 把url的参数部分转化成json对象
     * @param {string} url
     * @returns {Object} 返回包含参数的json对象中
     */
    static parseURLQueryString (url) {
        var reg_url = /^[^\?]+\?([\w\W]+)$/,
            reg_para = /([^&=]+)=([\w\W]*?)(&|$|#)/g,
            arr_url = reg_url.exec(url),
            ret = {};
        if (arr_url && arr_url[1]) {
            var str_para = arr_url[1], result;
            while ((result = reg_para.exec(str_para)) != null) {
                ret[result[1]] = result[2];
            }
        }
        return ret;
    }

    /**
     * 支持浏览器:是<br>
     * 构建带查询参数的url
     * @param {string|Object} url 需要附加参数的url
     * @param {Object|undefined} parameters 查询参数比如{"name":"小主", "age":"18"}
     * @returns {string} 返回处理后的url
     */
    static URL(url, parameters) {
        let newUrl = url;
        let params = parameters;
        if (!params) {
            params = url;
        }

        if (params) {
            var qString = "";
            let first = true;
            for ( let key in params)
            {
                // 编码解码函数:
                // escape/unescape/encodeURI/decodeURI/encodeURIComponent/decodeURIComponent
                qString += first ? "" : "&";
                first = false;
                qString += key + "=" + encodeURIComponent(params[key]);
            }
            if (!parameters) {
                return qString;
            }
            newUrl += "?" + qString;
        }
        return newUrl;
    }


    /**
     * 默认提交JSON数据,返回也默认解析为JSON,提交其他格式需要设置Content-Type。
     * 支持通过option.headers控制的Content-Type类型:
     * application/x-www-form-urlencoded;
     * application/json;
     * text/plain
     * @param {String} url
     * @param {Object} httpBody 默认将被编译为JSON字符串提交到服务端
     * @param {Object} option {"headers":{额外的请求头},timeout:超时时间(浮点数单位秒)}
     * @returns {Task} 返回可打断的任务
     */
    static post(url, httpBody, option) {

        let newTask = new Task();
        newTask.name = "http.post";

        // 默认值
        let contentType = "application/json";
        let timeout = 5.0;
        let headers = {};

        if (option && option.headers) {
            headers = option.headers;
        }

        if (headers["Content-Type"]) {
            contentType = headers["Content-Type"];
        } else {
            headers["Content-Type"] = "application/json";
        }

        if (option && option.timeout) {
            timeout = option.timeout;
        }

        // 标准的判断是否在浏览器环境, 编译的时候自动删除
        if (!Native.getInstance().isHos()) {
            let task = new XMLHttpRequest();

            task.ontimeout = ()=> {
                newTask.__reject({"errMsg": "网络请求超时"});
            };

            task.onreadystatechange = ()=>{
                if (task.readyState === 4) {
                    if (task.status === 200) {
                        let text = task.responseText;
                        try {
                            newTask.__resolve(JSON.parse(text));
                        } catch (error) {
                            newTask.__resolve(text);
                        }
                    } else {
                        newTask.__reject({"errMsg": task.status + "错误"});
                    }
                }
            };

            task.open("POST", url, true);

            if (headers) {
                for (let key in headers) {
                    // 该操作需要在open后
                    task.setRequestHeader(key, "" + headers[key]);
                }
            }

            if (contentType.indexOf("application/json") == 0) {
                task.send(JSON.stringify(httpBody));
            } else if (contentType.indexOf("application/x-www-form-urlencoded") == 0) {
                let requestText = http.URL(httpBody);
                console.log("[http]提交url编码数据" + requestText);
                task.send(requestText);
            }

            newTask.__setAbort(()=>{
                task.abort();
            });

            return newTask;
        }

        let requestText = null;

        if (contentType.indexOf("application/json") == 0) {
            requestText = JSON.stringify(httpBody);
        } else if (contentType.indexOf("application/x-www-form-urlencoded") == 0) {
            requestText = http.URL(httpBody);
        } else if (contentType.indexOf("text/plain") == 0) {
            requestText = httpBody; // 直接上传文本
        }

        let task = Native.getInstance().callNative("http", {
            "url": url,
            "method": "post",
            "requestText": requestText,
            "headers": headers,
            "timeout": timeout
        }, true, data=>{
            let text= data.msg;
            try {
                newTask.__resolve(JSON.parse(text));
            } catch (error) {
                newTask.__resolve(text);
            }
        }, error=>{newTask.__reject(error);});

        newTask.__setAbort(()=>{task.abort();});

        return newTask;
    }

    /**
      * 支持浏览器:是，可能要配置跨域选项<br>
      * 用于发送简单的GET请求，只支持请求JSON等文本场合。更多的HTTP操作请使用类Http。
      * @param {string} url
      * @param {Object|undefined} parameters 查询参数比如{"name":"小主", "age":"18"}；
      *                            参数会被编码到url后，但是如果你自己已经添加了?，就不要再使用该参数了
      * @param {Object|undefined} option 格式:{"text":true，返回文本，false/默认返回JSON对象, "headers":额外的请求头}
      * @returns {Task} 失败:{"errMsg":错误描述} 成功:JSON对象或者文本
      */
    static get(url, parameters = undefined, option = undefined) {

        if (parameters) {
            url = http.URL(url, parameters);
        }

        let newTask = new Task();
        newTask.name = "http.get";

        let headers = {};

        if (option && option.headers) {
            headers = option.headers;
        }

        if (!Native.getInstance().isHos()) {
            let task = new XMLHttpRequest();
            task.ontimeout = ()=> {
                newTask.__reject({"errMsg": "网络请求超时"});
            };
            task.onreadystatechange = ()=>{
                if (task.readyState === 4) {
                    if (task.status === 200) {
                        let text= task.responseText;
                        try {
                            newTask.__resolve(JSON.parse(text));
                        } catch (error) {
                            newTask.__reject(text);
                        }
                    } else {
                        newTask.__reject({"errMsg": task.status + "错误"});
                    }
                }
            };
            task.open("GET", url, true);
            if (headers) {
                for (let key in headers) {
                    task.setRequestHeader(key, "" + headers[key]);
                }
            }
            task.send(null);
            newTask.__setAbort(()=>{task.abort();});
            return newTask;
        }

        let task = Native.getInstance().callNative("http", {
            "url": url,
            "method": "get",
            "headers": headers
        }, true, data=>{
            let text= data.msg;
            try {
                newTask.__resolve(JSON.parse(text));
            } catch (error) {
                newTask.__resolve(text);
            }
        }, error=>{newTask.__reject(error);});
        newTask.__setAbort(()=>{task.abort();});
        return newTask;
    }

    /**
     * 注意该方法为同步方法，大文件建议使用异步方法
     * @param {String} path
     * @returns {XMLHttpRequest} XMLHttpRequest对象
     */
    static xhr(path) {
        let xhr = new XMLHttpRequest();
        xhr.open("get", path, false);
        xhr.send(null);
        return xhr;
    }


    /**
      * 支持浏览器:是，可能要配置跨域选项<br>
      * 使用XMLHttpRequest发送get请求，错误或者成功都可以获得XMLHttpRequest对象
      * @param {string} url
      * @param {Object} parameters 查询参数比如{"name":"小主", "age":"18"}；
      *                            参数会被编码到url后，但是如果你自己已经添加了?，就不要再使用该参数了
      * @param {Object} option 格式:{"headers":额外的请求头}
      * @returns {Task} 失败回调参考:XMLHttpRequest对象 成功回调参考:XMLHttpRequest对象
      */
    static getByXhr(url, parameters, option) {
        if (parameters) {
            url = http.URL(url, parameters);
        }
        let newTask = new Task();
        newTask.name = "http.getByXhr";
        let headers = {};
        if (option && option.headers) {
            headers = option.headers;
        }
        let task = new XMLHttpRequest();
        task.responseType = "blob";
        task.ontimeout = ()=> {
            newTask.__reject(task);
        };
        task.onreadystatechange = ()=>{
            if (task.readyState === 4) {
                // webview特殊的情况，没有填写状态码（状态码为0），因此此种情况也当成功
                if (task.status === 200 || task.status === 0 && task.response) {
                    newTask.__resolve(task);
                } else {
                    newTask.__reject(task);
                }
            }
        };
        task.open("GET", url, true);
        if (headers) {
            for (let key in headers) {
                task.setRequestHeader(key, "" + headers[key]);
            }
        }
        task.send(null);
        newTask.__setAbort(()=>{task.abort();});
        return newTask;
    }

}
export {http};
